/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief Simple module for storing and fetching message replies.
 * \author Antti Maula <antti.maula@tkk.fi>
 */
#ifndef _GIMNETAP_MSGREPLYBUFFER_KJHAKSDH_H_
#define _GIMNETAP_MSGREPLYBUFFER_KJHAKSDH_H_
#include <inttypes.h>
#include "ownutils.h"
#include "idmap.h"

#ifdef __cplusplus
extern "C" {
#endif
  
/** Structure for MsgReplyBuffer instance storage
 *
 */
typedef struct SMsgReplyBuffer
{
  ownMutexHandle lock; ///< Mutex handle
  ownCondHandle cond; ///< Condition handle
  TIDMap messageMap; ///< map of messages utilizing idmap.
} TMsgReplyBuffer;

typedef struct SMsgReplyBufferEntry
{
  int signaled; ///< State of entry; Signaled or not?
  uint32_t message_id; ///< Messages id (the key)
  uint32_t timestamp_s; ///< Timestamp of entry
  void *query; ///< User-defined query pointer (just stored, nothing else)
  void *reply; ///< User-defined reply pointer (just stored, nothing else)
} TMsgReplyBufferEntry;


/** Initialize replybuffer instance.
 * 
 * @param[in] b Pointer to structure to initialize.
 */
void msgreplybufferInit(TMsgReplyBuffer *b);


/** Deinitialize replybuffer instance.
 * 
 * @param[in] b Pointer to structure to deinitialize.
 */
void msgreplybufferDeinit(TMsgReplyBuffer *b);


/** Insert new message to replybuffer.
 * 
 * This function inserts a new message to replybuffer, keyed with
 * value msgid, accompadiend
 * 
 * @param[in] b Pointer to TMsgReplyBuffer structure
 * @param[in] msgid MessageId key
 * @param[in] query Pointer to some user-defined data.
 * @return Zero on success, non-zero on error (element already exists)
 */
int msgreplybufferInsertMsg(TMsgReplyBuffer *b,const uint32_t msgid, void *query);


/** Lock the given MsgReplyBuffer.
 * 
 * @param[in] b Pointer to TMsgReplyBuffer structure
 */
void msgreplybufferLock(TMsgReplyBuffer *b);


/** Unlock the given MsgReplyBuffer.
 * 
 * @param[in] b Pointer to TMsgReplyBuffer structure
 */
void msgreplybufferUnlock(TMsgReplyBuffer *b);


/** Synchronously wait for a reply with given key to become available, or until timeout expires.
 *
 * @param[in] b Pointer to TMsgReplyBuffer structure
 * @param[out] entry If reply is received, the data is stored to this pointer
 * @param[in] msgid Message identifier to look for
 * @param[in] timeout_ms Maximum time in milliseconds to wait for reply.
 * @return Zero when reply received and stored to \p entry, non-zero on any error (timeout, etc)
 */
int msgreplybufferWaitReply(TMsgReplyBuffer *b,
                            TMsgReplyBufferEntry *entry, 
                            const uint32_t msgid, 
                            const unsigned int timeout_ms);

/** Notify the given key and assign a pointer to user-defined reply data.
 *
 * This function will invoke the waiter (msgreplybufferWaitReply) for
 * the given key if such exists.
 * 
 * @param[in] b Pointer to TMsgReplyBuffer structure
 * @param[in] msgid Messageid key to notify
 * @param[in] reply Pointer to user-defined data bound to the reply.
 * @return Zero if key was found and notified, non-zero on error (no key found, etc)
 */
int msgreplybufferNotifyReply(TMsgReplyBuffer *b,
                              const uint32_t msgid, void *reply);


/** Clear the messagereplybuffer.
 *
 * This function invalidates and deletes all current  messagereplybuffers.
 * 
 * \todo This function does nothing to the user-defined pointers,
 * hence they will be left unfreed!
 * 
 * @param[in] b Pointer to TMsgReplyBuffer structure
 */
void msgreplybufferClear(TMsgReplyBuffer *b);


#ifdef __cplusplus
}
#endif

#endif
